/*
 * InvulgoTracker
 * Copyright (C) Thomas Andersen 2011 <thomas.1.andersen@gmail.com>
 *
 * InvulgoTracker is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * InvulgoTracker is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>

#include <config.h>

#include "gettextmacro.h"
#include "task-view.h"
#include "balanceview.h"
#include "day.h"
#include "invulgotrackerapp.h"
#include "prefs.h"

BalanceView::BalanceView()
{
    prevTime = NULL;
    prevName = NULL;
    totalWorkhours = 0;
    totalActual = 0;
}


BalanceView::~BalanceView()
{
    Clean();
}

void BalanceView::Clean()
{
    g_object_unref (model);
    gtk_tree_view_set_model (view, NULL);
    while (gtk_tree_view_remove_column(view, gtk_tree_view_get_column(view, 0)) > 0);
}

void BalanceView::Restart()
{
    Clean();
    Init(GTK_WIDGET(view), isSortable);
}

GtkTreeModel *BalanceView::CreateModel()
{
    GtkListStore  *store;

    store = gtk_list_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_LONG, G_TYPE_LONG);

    return GTK_TREE_MODEL (store);
}


extern "C" gint BalanceView::sort_iter_compare_func_date(GtkTreeModel *model, GtkTreeIter  *a, GtkTreeIter  *b, gpointer userdata)
{
    BalanceView *sv = (BalanceView*)userdata;
    return sv->sort_iter_compare_func(model, a, b, GINT_TO_POINTER(SORT_DATE));
}

extern "C" gint BalanceView::sort_iter_compare_func_workhours(GtkTreeModel *model, GtkTreeIter  *a, GtkTreeIter  *b, gpointer userdata)
{
    BalanceView *sv = (BalanceView*)userdata;
    return sv->sort_iter_compare_func(model, a, b, GINT_TO_POINTER(SORT_WORKHOURS));
}

extern "C" gint BalanceView::sort_iter_compare_func_actual(GtkTreeModel *model, GtkTreeIter  *a, GtkTreeIter  *b, gpointer userdata)
{
    BalanceView *sv = (BalanceView*)userdata;
    return sv->sort_iter_compare_func(model, a, b, GINT_TO_POINTER(SORT_ACTUAL));
}

gint BalanceView::sort_iter_compare_func (GtkTreeModel *model, GtkTreeIter  *a, GtkTreeIter  *b, gpointer userdata)
{
    gint sortcol = GPOINTER_TO_INT(userdata);
    gint ret = 0;
    /* Sort by content. */
    switch (sortcol)
    {
    case BalanceView::SORT_DATE:
        {
            gchar *name1, *name2;

            gtk_tree_model_get(model, a, BalanceView::COL_DATE, &name1, -1);
            gtk_tree_model_get(model, b, BalanceView::COL_DATE, &name2, -1);

            if (name1 == NULL || name2 == NULL)
            {
                if (name1 == NULL && name2 == NULL)
                    break; /* both equal => ret = 0 */

                ret = (name1 == NULL) ? -1 : 1;
            }
            else
            {
                ret = g_utf8_collate(name1,name2);
            }

            g_free(name1);
            g_free(name2);
        }
        break;
    case BalanceView::SORT_WORKHOURS:
        {
            long hour1,hour2;

            gtk_tree_model_get(model, a, BalanceView::COL_WORKHOURS, &hour1, -1);
            gtk_tree_model_get(model, b, BalanceView::COL_WORKHOURS, &hour2, -1);

            if (hour1 < hour2)
                ret = -1;
            else if (hour1 == hour2)
                ret = 0;
            else
                ret = 1;
        }
        break;
    case BalanceView::SORT_ACTUAL:
        {
            long hour1,hour2;

            gtk_tree_model_get(model, a, BalanceView::COL_ACTUAL, &hour1, -1);
            gtk_tree_model_get(model, b, BalanceView::COL_ACTUAL, &hour2, -1);

            if (hour1 < hour2)
                ret = -1;
            else if (hour1 == hour2)
                ret = 0;
            else
                ret = 1;
        }
        break;

    default:
        g_return_val_if_reached(0);
    }
    return ret;
}

extern "C" void BalanceView::column_date_clicked(GtkTreeViewColumn *treeviewcolumn, gpointer user_data)
{
    BalanceView *sv = (BalanceView*)user_data;
    GtkTreeSortable *sortable;
    GtkSortType      order;
    gint             sortid;

    sortable = GTK_TREE_SORTABLE(sv->model);

    /* If we are already sorting by year, reverse sort order,
     *  otherwise set it to year in ascending order */
    g_object_set(treeviewcolumn, "sort-indicator", TRUE ,NULL);
    if (gtk_tree_sortable_get_sort_column_id(sortable, &sortid, &order) == TRUE &&  sortid == SORT_DATE) {
        GtkSortType neworder;
        neworder = (order == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING : GTK_SORT_ASCENDING;
        gtk_tree_sortable_set_sort_column_id(sortable, SORT_DATE, neworder);
        g_object_set(treeviewcolumn, "sort-order", neworder ,NULL);
    } else {
        GList *list = gtk_tree_view_get_columns(sv->view);
        do {
            if (list && list->data != treeviewcolumn)
                g_object_set(list->data, "sort-indicator", FALSE ,NULL);
        } while((list = g_list_next(list)));
        g_list_free(list);
        gtk_tree_sortable_set_sort_column_id(sortable, SORT_DATE, GTK_SORT_ASCENDING);
        g_object_set(treeviewcolumn, "sort-order", GTK_SORT_ASCENDING ,NULL);
    }
}

extern "C" void BalanceView::column_workhours_clicked(GtkTreeViewColumn *treeviewcolumn, gpointer user_data)
{
    BalanceView *sv = (BalanceView*)user_data;
    GtkTreeSortable *sortable;
    GtkSortType      order;
    gint             sortid;

    sortable = GTK_TREE_SORTABLE(sv->model);

    /* If we are already sorting by year, reverse sort order,
     *  otherwise set it to year in ascending order */

    g_object_set(treeviewcolumn, "sort-indicator", TRUE ,NULL);
    if (gtk_tree_sortable_get_sort_column_id(sortable, &sortid, &order) == TRUE &&  sortid == SORT_WORKHOURS) {
        GtkSortType neworder;
        neworder = (order == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING : GTK_SORT_ASCENDING;
        gtk_tree_sortable_set_sort_column_id(sortable, SORT_WORKHOURS, neworder);
        g_object_set(treeviewcolumn, "sort-order", neworder ,NULL);
    } else {
        GList *list = gtk_tree_view_get_columns(sv->view);
        do {
            if (list && list->data != treeviewcolumn)
                g_object_set(list->data, "sort-indicator", FALSE ,NULL);
        } while((list = g_list_next(list)));
        g_list_free(list);
        gtk_tree_sortable_set_sort_column_id(sortable, SORT_WORKHOURS, GTK_SORT_ASCENDING);
        g_object_set(treeviewcolumn, "sort-order", GTK_SORT_ASCENDING ,NULL);
    }
}

extern "C" void BalanceView::column_actual_clicked(GtkTreeViewColumn *treeviewcolumn, gpointer user_data)
{
    BalanceView *sv = (BalanceView*)user_data;
    GtkTreeSortable *sortable;
    GtkSortType      order;
    gint             sortid;

    sortable = GTK_TREE_SORTABLE(sv->model);

    /* If we are already sorting by year, reverse sort order,
     *  otherwise set it to year in ascending order */

    g_object_set(treeviewcolumn, "sort-indicator", TRUE ,NULL);
    if (gtk_tree_sortable_get_sort_column_id(sortable, &sortid, &order) == TRUE &&  sortid == SORT_ACTUAL) {
        GtkSortType neworder;
        neworder = (order == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING : GTK_SORT_ASCENDING;
        gtk_tree_sortable_set_sort_column_id(sortable, SORT_ACTUAL, neworder);
        g_object_set(treeviewcolumn, "sort-order", neworder ,NULL);
    } else {
        GList *list = gtk_tree_view_get_columns(sv->view);
        do {
            if (list && list->data != treeviewcolumn)
                g_object_set(list->data, "sort-indicator", FALSE ,NULL);
        } while((list = g_list_next(list)));
        g_list_free(list);
        gtk_tree_sortable_set_sort_column_id(sortable, SORT_ACTUAL, GTK_SORT_ASCENDING);
        g_object_set(treeviewcolumn, "sort-order", GTK_SORT_ASCENDING ,NULL);
    }
}

void BalanceView::Init(GtkWidget *view, gboolean sortable)
{
    GtkCellRenderer *renderer;

    this->isSortable = sortable;
    this->view = GTK_TREE_VIEW(view);

    model = CreateModel();
    renderer = gtk_cell_renderer_text_new ();
    GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(_("Item"),  renderer, "text", COL_DATE, NULL);
    //    gtk_tree_view_column_set_resizable(column, TRUE);
    g_object_set(column, "sizing",GTK_TREE_VIEW_COLUMN_AUTOSIZE,NULL);
    if (sortable) {
        g_object_set(column, "reorderable", TRUE ,NULL);
        g_object_set(column, "clickable", TRUE ,NULL);
        g_object_set(column, "sort-indicator", TRUE ,NULL);
        g_signal_connect(G_OBJECT(column), "clicked", G_CALLBACK(column_date_clicked), this);
    }
    gtk_tree_view_insert_column(GTK_TREE_VIEW (view), column, -1);

    // Workhours
    renderer = gtk_cell_renderer_text_new ();
    g_object_set(renderer, "xalign",1.0,NULL);
     column = gtk_tree_view_column_new_with_attributes(_("Workhours"),  renderer, "text", COL_WORKHOURS, NULL);
    if (sortable) {
        g_object_set(column, "reorderable", TRUE ,NULL);
        g_object_set(column, "clickable", TRUE ,NULL);
        g_signal_connect(G_OBJECT(column), "clicked", G_CALLBACK(column_workhours_clicked), this);
        GtkTreeSortable *sortable = GTK_TREE_SORTABLE(model);
        gtk_tree_sortable_set_sort_func(sortable, SORT_DATE, sort_iter_compare_func_date,this, NULL);
        gtk_tree_sortable_set_sort_func(sortable, SORT_WORKHOURS, sort_iter_compare_func_workhours,this, NULL);
        /* set initial sort order */
        gtk_tree_sortable_set_sort_column_id(sortable, SORT_DATE, GTK_SORT_ASCENDING);
    }
    gtk_tree_view_insert_column(GTK_TREE_VIEW (view), column, -1);

    // Workhours
    renderer = gtk_cell_renderer_text_new ();
    g_object_set(renderer, "xalign",1.0,NULL);
     column = gtk_tree_view_column_new_with_attributes(_("Actual"),  renderer, "text", COL_ACTUAL, NULL);
    if (sortable) {
        g_object_set(column, "reorderable", TRUE ,NULL);
        g_object_set(column, "clickable", TRUE ,NULL);
        g_signal_connect(G_OBJECT(column), "clicked", G_CALLBACK(column_actual_clicked), this);
        GtkTreeSortable *sortable = GTK_TREE_SORTABLE(model);
        gtk_tree_sortable_set_sort_func(sortable, SORT_DATE, sort_iter_compare_func_date,this, NULL);
        gtk_tree_sortable_set_sort_func(sortable, SORT_ACTUAL, sort_iter_compare_func_actual,this, NULL);
        /* set initial sort order */
        gtk_tree_sortable_set_sort_column_id(sortable, SORT_DATE, GTK_SORT_ASCENDING);
    }
    gtk_tree_view_insert_column(GTK_TREE_VIEW (view), column, -1);

    gtk_tree_view_set_model (GTK_TREE_VIEW (view), model);

}

void BalanceView::CalcDay(guint year, guint month, guint day)
{
    GtkTreeIter iter = {0};
    Prefs prefs;

    TaskTime tt(year, month + 1, day);
    double workhours = prefs.GetWorkhours(tt.GetWeekDay()) / 60;
    totalWorkhours += workhours;


    Day dayloader(year, month, day);

    totalTime.TimeFromString((char*)"00:00");

    dayloader.Load(this);

    if (prevTime) {
        delete prevTime;
        prevTime = NULL;
    }

    if (prevName) {
        free(prevName);
        prevName = NULL;
    }

    totalActual += totalTime.Minutes() / 60;

    long totTime = totalTime.Minutes() / 60;
    char *dateText = tt.DateText();
    gtk_list_store_append (GTK_LIST_STORE(model), &iter);
    gtk_list_store_set (GTK_LIST_STORE(model), &iter,
                        COL_DATE, dateText,
                        COL_ACTUAL, totTime,
                        COL_WORKHOURS, (long)workhours,
                        -1);
    free(dateText);
}


void BalanceView::Data(gchar *name, gchar *timeStr, TaskId id)
{
    TaskTime taskTime;
    taskTime.TimeFromString(timeStr);
    free(timeStr);
    free(name);
    if (prevTime) {
        TaskTime diff = taskTime.SubTime(*prevTime);
        totalTime = totalTime.AddTime(diff);
        delete prevTime;
        prevTime = NULL;
    }
    prevTime = new TaskTime(taskTime);
}


bool BalanceView::GetFirst(gchar **name, gchar **timeStr)
{
    if (gtk_tree_model_get_iter_first(model, &currentIter)) {
        gtk_tree_model_get(model, &currentIter,
                           COL_DATE, name,
                           COL_WORKHOURS, timeStr,
                           -1);
        return true;
    }
    return false;
}

bool BalanceView::GetNext(gchar **name, gchar **timeStr)
{
    if (gtk_tree_model_iter_next(model, &currentIter)) {
        gtk_tree_model_get(model, &currentIter,
                           COL_DATE, name,
                           COL_WORKHOURS, timeStr,
                           -1);
        return true;
    }
    return false;
}




